package com.apes.fn.crm.ReturnVisit.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.apes.fn.crm.ReturnVisit.model.VisitHistory;
import com.apes.fn.crm.ReturnVisit.model.VisitStatistics;
import com.apes.fn.crm.ReturnVisit.repository.ReturnVisitDao;
import com.apes.fn.crm.ReturnVisit.repository.VisitHistoryRepository;
import com.apes.fn.crm.ReturnVisit.repository.VisitReportDao;
import com.apes.fn.crm.ReturnVisit.repository.VisitStatisticsRepository;
import com.apes.framework.api.DomainService;
import com.apes.framework.jpa.spec.JpaDsl;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.util.DateUtil;
import com.apes.framework.util.MapUtil;
import com.apes.framework.util.Tools;
import com.apes.scm.masterdata.enumeration.model.Enumeration;
import com.apes.scm.masterdata.enumeration.repository.EnumerationRepository;
import com.apes.scm.masterdata.party.model.PartyRole;
import com.apes.scm.masterdata.party.repository.PartyRoleRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;

import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Service("visitReportService")
public class VisitReportService extends DomainService {


    @Autowired
    VisitHistoryRepository visitHistoryRepository;
    @Autowired
    EnumerationRepository enumerationRepository;
    @Autowired
    VisitStatisticsRepository visitStatisticsRepository;
    @Autowired
    ReturnVisitDao returnVisitDao;
    @Autowired
    VisitReportDao visitReportDao;
    @Autowired
    PartyRoleRepository partyRoleRepository;

    /***
     * 回访满意度分析
     */

    public Map getVisitSatisfactionAnalysis(SimpleRequest request) {

        Map condition = parseCondition(request);

        List<VisitHistory> visitHistories = visitHistoryRepository.findAll(
                JpaDsl.toCriteriaIgnoreNull(
                        "visitedDate", "GTE", condition.get("CALCULATE_DATE_START"),
                        "visitedDate", "LTE", condition.get("CALCULATE_DATE_END"),
                        "returnVisit.dept.id", "EQ", condition.get("DEPT_ID"),
                        "state", "EQ", "finish"
                )
        );
        JSONArray content = new JSONArray();
        if (visitHistories.size() != 0) {
            // 根据部门进行分组
            Map<String, List<VisitHistory>> groupByDeptName = visitHistories.stream().collect(Collectors.groupingBy(visitHistory -> {
                return visitHistory.getReturnVisit().getDept().getName();
            }));
            DecimalFormat df = new DecimalFormat("0.00%");
            // 计算每一种类型
            groupByDeptName.keySet().forEach(deptName -> {
                JSONObject tempJson = new JSONObject();
                List<VisitHistory> tempList = groupByDeptName.get(deptName);

                tempJson.put("deptName", deptName);
                tempJson.put("visitNumber", tempList.size());
                tempJson.put("veryUnsatisfied", tempList.stream().
                        filter(visitHistory -> visitHistory.getVisitSatisfaction().getId().equals("VisitHistory.visitSatisfaction.-2")).count());
                tempJson.put("unsatisfied", tempList.stream().
                        filter(visitHistory -> visitHistory.getVisitSatisfaction().getId().equals("VisitHistory.visitSatisfaction.-1")).count());
                tempJson.put("average", tempList.stream().
                        filter(visitHistory -> visitHistory.getVisitSatisfaction().getId().equals("VisitHistory.visitSatisfaction.0")).count());
                tempJson.put("satisfied", tempList.stream().
                        filter(visitHistory -> visitHistory.getVisitSatisfaction().getId().equals("VisitHistory.visitSatisfaction.1")).count());
                tempJson.put("verySatisfied", tempList.stream().
                        filter(visitHistory -> visitHistory.getVisitSatisfaction().getId().equals("VisitHistory.visitSatisfaction.2")).count());
                tempJson.put("rate", tempJson.getIntValue("visitNumber") != 0 ?
                        df.format((tempJson.getIntValue("satisfied") + tempJson.getIntValue("verySatisfied")) / tempJson.getIntValue("visitNumber")) : "0%");
                content.add(tempJson);
            });
        }
        return MapUtil.mapper(
                "content", content,
                "total", content.size(),
                "size", content.size()
        );
    }


    /***
     * 不满意原因分析
     */

    public Map<String, Object> getUnsatisfactionReasonAnalysis(SimpleRequest request) {

        // 解析条件: 开始结束时间, 业务部门 不满意原因
        Map condition = parseCondition(request);

        List<String> visitSatisfaction = new ArrayList();
        visitSatisfaction.add("VisitHistory.visitSatisfaction.-2");
        visitSatisfaction.add("VisitHistory.visitSatisfaction.-1");
        List<VisitHistory> visitHistories = visitHistoryRepository.findAll(
                JpaDsl.toCriteriaIgnoreNull(
                        "visitedDate", "GTE", condition.get("CALCULATE_DATE_START"),
                        "visitedDate", "LTE", condition.get("CALCULATE_DATE_END"),
                        "returnVisit.dept.id", "EQ", condition.get("DEPT_ID"),
                        "visitDissatisfactionReason.id", "EQ", condition.get("VISIT_DISSATISFACTION_REASON"),
                        "visitSatisfaction.id", "IN", visitSatisfaction,
                        "state", "EQ", "finish"
                )
        );
        if (visitHistories.size() != 0) {
            // 根据部门进行分组
            Map<String, List<VisitHistory>> groupByDeptName = visitHistories.stream().collect(Collectors.groupingBy(visitHistory -> {
                return visitHistory.getReturnVisit().getDept().getName();
            }));


            // 构建表头
            JSONArray tableHeader = new JSONArray();
            List<Enumeration> headers = condition.get("VISIT_DISSATISFACTION_REASON") == null ?
                    enumerationRepository.findAll(
                            JpaDsl.toCriteriaByEq(
                                    "type.id", "visitDissatisfactionReason"
                            ), new Sort(Sort.Direction.DESC, "id")
                    ) : enumerationRepository.findAll(
                    JpaDsl.toCriteriaByEq(
                            "id", condition.get("VISIT_DISSATISFACTION_REASON")
                    )
            );


            headers.forEach(header -> {
                tableHeader.add(header.getDescription());
            });


            // 获取数据
            JSONArray content = new JSONArray();
            JSONArray footer = new JSONArray();
            JSONObject footerJson = new JSONObject();
            groupByDeptName.keySet().stream().forEach(deptName -> {
                JSONObject tempJson = new JSONObject();
                List<VisitHistory> tempList = groupByDeptName.get(deptName);

                tempJson.put("deptName", deptName);
                tempJson.put("companyName", tempList.get(0).getReturnVisit().getCompany().getName());

                headers.forEach(header -> {
                    tempJson.put(header.getDescription(), tempList.stream().filter(item -> item.getVisitDissatisfactionReason().getId().equals(header.getId())).count());
                    footerJson.put(header.getDescription(), footerJson.getIntValue(header.getDescription()) + tempJson.getIntValue(header.getDescription()));
                });
                content.add(tempJson);
            });

            footer.add(footerJson);

            return MapUtil.mapper(
                    "content", content,
                    "total", content.size(),
                    "size", content.size(),
                    "tableHeader", getTableHeader(headers),
                    "footer", footer
            );
        }
        return MapUtil.mapper(
                "content", new JSONArray(),
                "total", 0,
                "size", 50,
                "tableHeader", getTableHeader(new ArrayList()),
                "footer", new JSONArray()
        );
    }


    /***
     * 回访量统计
     */


    public Map<String, Object> getVisitStatistics(SimpleRequest request) {
        Map condition = parseCondition(request);

        this.invoke("fn.returnVisit.getVisitStatisticsByDate", MapUtil.mapper(
                "taskDate", DateUtil.format(DateUtil.SHOW_DATE_FORMAT)
        ));
        JSONArray visitStatistics = visitReportDao.getVisitStatistics(parseDate(condition));
//        List<VisitStatistics> visitStatistics = visitStatisticsRepository.findAll(
//                JpaDsl.toCriteriaIgnoreNull(
//                    "visitor.id", "EQ", condition.get("visitor"),
//                        "insertDate", "GTE", condition.get("CALCULATE_DATE_START"),
//                        "insertDate", "LTE", condition.get("CALCULATE_DATE_END")
//                ), new Sort(Sort.Direction.ASC, "visitor", "insertDate")
//        );


        return MapUtil.mapper(
                "content", visitStatistics,
                "total", visitStatistics.size(),
                "size", visitStatistics.size()
        );

    }

    private JSONObject parseDate(Map condition){
        JSONObject parm = new JSONObject();
        String show_type = (String)condition.get("SHOW_TYPE");
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        parm.put("date",sdf.format((Date) condition.get("CALCULATE_DATE_START")));
        switch (show_type){
            case "0":
                parm.put("parse","YYYY-MM-DD");
                parm.put("date","DD");
                break;
            case "1":
                parm.put("parse","YYYY-MM");
                sdf = new SimpleDateFormat("yyyy-MM");
                parm.put("date","MM");
                break;
            case "2":
                parm.put("parse","YYYY");
                sdf = new SimpleDateFormat("yyyy");
                parm.put("date","YYYY");
                break;
                default:
                    throw new RuntimeException("未知类型");
        }

        if (condition.get("CALCULATE_DATE_END")!=null)parm.put("end",sdf.format((Date) condition.get("CALCULATE_DATE_END")));
        if (condition.get("CALCULATE_DATE_START")!=null)parm.put("start",sdf.format((Date) condition.get("CALCULATE_DATE_START")));
        if (condition.get("visitor")!=null)parm.put("visitor",condition.get("visitor"));
        parm.put("SHOW_TYPE",show_type);
        return parm;

    }
    /***
     * 解析条件
     */
    private Map parseCondition(SimpleRequest request) {
        JSONArray condition = request.getJO().getJSONArray("condition");
        Map returnMap = new HashMap();
        condition.stream().forEach(json -> {
            JSONObject obj = (JSONObject) json;

            if (obj.getString("type") == null) {
                returnMap.put(obj.getString("field"), obj.getString("value"));
            } else if (obj.getString("type").equals("date") && obj.getString("operator").equals("GTE")) {
                returnMap.put(obj.getString("field") + "_START", DateUtil.parse(obj.getString("value"), DateUtil.SHOW_DATETIME_FORMAT));
            } else if (obj.getString("type").equals("date") && obj.getString("operator").equals("LTE")) {
                returnMap.put(obj.getString("field") + "_END", DateUtil.parse(obj.getString("value"), DateUtil.SHOW_DATETIME_FORMAT));
            } else if (obj.getString("type").equals("date") && obj.getString("operator").equals("EQ")) {
                returnMap.put(obj.getString("field"), DateUtil.parse(obj.getString("value")));
            }
        });
        return returnMap;
    }


    /***
     * 构建表头
     */
    private List<Map> getTableHeader(List<Enumeration> headers) {
        List<Map> temp = headers.stream().map(header -> {
            return MapUtil.mapper(
                    "templateOptions", new HashMap(),
                    "expressionProperties", new HashMap(),
                    "hooks", new HashMap(),
                    "headerName", header.getDescription(),
                    "sum", true,
                    "field", header.getDescription(),
                    "cellEditor", "input"
            );
        }).collect(Collectors.toList());

        temp.add(0, MapUtil.mapper(
                "templateOptions", new HashMap(),
                "expressionProperties", new HashMap(),
                "hooks", new HashMap(),
                "headerName", "部门",
                "field", "deptName",
                "cellEditor", "input"
        ));

        temp.add(1, MapUtil.mapper(
                "templateOptions", new HashMap(),
                "expressionProperties", new HashMap(),
                "hooks", new HashMap(),
                "headerName", "公司",
                "field", "companyName",
                "cellEditor", "input"
        ));
        return temp;
    }

    /***
     * 获取回访量统计(日结，或者获取当前值)
     */
    public void getVisitStatisticsByDate(SimpleRequest request) {
        JSONObject returnJson = new JSONObject();
        JSONObject param = request.getJO();
        param.put("EXECUTE_DATE", DateUtil.parse(param.getString("taskDate")));

        getAdd(param, returnJson);
        getWaitVisit(param, returnJson);
        getVisited(param, returnJson);
        getShouldVisit(returnJson);
        getShouldVisit(returnJson);
        getFinish(param, returnJson);
        getAgain(param, returnJson);
        getEnd(param, returnJson);
        getCall(param, returnJson);
        getRest(returnJson);
        getVisitedRate(returnJson);
        getSuccessVisitedRate(returnJson);


        // 删除已写入的数据
        List<VisitStatistics> visitStatisticsList = visitStatisticsRepository.findAll(
                JpaDsl.toCriteriaByEq("insertDate", DateUtil.parse(param.getString("taskDate")))
        );
        visitStatisticsRepository.deleteAll(visitStatisticsList);

        // 重新写入最新的数据
        returnJson.keySet().stream().forEach(key -> {
            JSONObject tempJson = returnJson.getJSONObject(key);
            VisitStatistics visitStatistics = Tools.map(tempJson, VisitStatistics.class);
            visitStatisticsRepository.save(visitStatistics);
        });
    }

    // 上日剩余 今日新增 应回访 待回访 已回访 回访完成 继续回访 终止 已回访率 回访成功率 拨号量

    /***
     * 获取上日剩余
     */
    private void getRest(JSONObject returnJson) {

        returnJson.keySet().stream().forEach( key -> {
            JSONObject tempJson = returnJson.getJSONObject(key);
            tempJson.put("qtyRest",
                    tempJson.getIntValue("qtyShouldVisit") - tempJson.getIntValue("qtyAdd"));
            returnJson.put(key, tempJson);
        });
    }

    /***
     * 获取今日新增
     */
    private void getAdd(JSONObject param, JSONObject returnJson) {
        JSONArray array = returnVisitDao.getAdd(param);
        resolveData(array, returnJson, param, "qtyAdd", "ADD_NUM");
    }

    /***
     * 获取应回访
     */
    private void getShouldVisit(JSONObject returnJson) {
        returnJson.keySet().stream().forEach( key -> {
            JSONObject tempJson = returnJson.getJSONObject(key);
            tempJson.put("qtyShouldVisit",
                    tempJson.getIntValue("qtyWaitVisit") + tempJson.getIntValue("qtyVisited"));
            returnJson.put(key, tempJson);
        });
    }

    /***
     * 获取待回访
     */
    private void getWaitVisit(JSONObject param, JSONObject returnJson) {
        JSONArray array = returnVisitDao.getWaitVisit(param);
        resolveData(array, returnJson, param, "qtyWaitVisit", "WAIT_VISIT");
    }

    /***
     * 获取已回访
     */
    private void getVisited(JSONObject param, JSONObject returnJson) {
        JSONArray array = returnVisitDao.getVisited(param);
        resolveData(array, returnJson, param, "qtyVisited", "VISITED");
    }

    /***
     * 获取回访完成
     */
    private void getFinish(JSONObject param, JSONObject returnJson) {
        JSONArray array = returnVisitDao.getVisited(param);
        resolveData(array, returnJson, param, "qtyFinish", "FINISH_NUM");
    }

    /***
     * 获取终止
     */
    private void getEnd(JSONObject param, JSONObject returnJson) {
        JSONArray array = returnVisitDao.getEnd(param);
        resolveData(array, returnJson, param, "qtyEnd", "END_NUM");
    }

    /***
     * 获取继续回访
     */
    private void getAgain(JSONObject param, JSONObject returnJson) {

    }

    /***
     * 获取拨号量
     */
    private void getCall(JSONObject param, JSONObject returnJson) {
        JSONArray array = returnVisitDao.getEnd(param);
        resolveData(array, returnJson, param, "qtyCall", "getCall");
    }

    /***
     * 获取已回访率
     */
    private void getVisitedRate(JSONObject returnJson) {
        DecimalFormat df = new DecimalFormat("0.00%");
        returnJson.keySet().stream().forEach( key -> {
            JSONObject tempJson = returnJson.getJSONObject(key);
            if( tempJson.getIntValue("qtyShouldVisit") == 0 ) return;
            tempJson.put("visitedRate",
                    df.format(tempJson.getIntValue("qtyVisited") / tempJson.getIntValue("qtyShouldVisit")));
            returnJson.put(key, tempJson);
        });
    }

    /***
     * 获取回访完成率
     */
    private void getSuccessVisitedRate(JSONObject returnJson) {
        DecimalFormat df = new DecimalFormat("0.00%");
        returnJson.keySet().stream().forEach( key -> {
            JSONObject tempJson = returnJson.getJSONObject(key);
            if( tempJson.getIntValue("qtyVisited") == 0 ) return;
            tempJson.put("visitedSuccessRate",
                    df.format(tempJson.getIntValue("qtyFinish") + tempJson.getIntValue("qtyVisited")));
            returnJson.put(key, tempJson);
        });
    }


    /***
     * 处理数据
     */
    private void resolveData(JSONArray array, JSONObject returnJson, JSONObject param, String field, String column) {

        array.stream().forEach(json -> {
            JSONObject obj = (JSONObject) json;
            JSONObject row;

            // 存在回访人为空的情况
            if( obj.get("VISITOR_ID") == null ){
                obj.put("VISITOR_ID", "未分配");
            }

            if (returnJson.get(obj.getString("VISITOR_ID")) == null) {
                // 初始化数据
                row = new JSONObject();
                row.put("qtyRest",0);
                row.put("qtyAdd",0);
                row.put("qtyShouldVisit",0);
                row.put("qtyWaitVisit",0);
                row.put("qtyVisited",0);
                row.put("qtyFinish",0);
                row.put("qtyAgain",0);
                row.put("qtyEnd",0);
                row.put("qtyCall",0);
                row.put("visitedRate","0.00%");
                row.put("visitedSuccessRate","0.00%");
                row.put("insertDate", DateUtil.parse(param.getString("EXECUTE_DATE")));

                if(!obj.getString("VISITOR_ID").equals("未分配")){
                    row.put("visitor", partyRoleRepository.findOne(obj.getString("VISITOR_ID")));
                }

            } else {
                row = returnJson.getJSONObject(obj.getString("VISITOR_ID"));
            }
            row.put(field, obj.getIntValue(column));
            returnJson.put(obj.getString("VISITOR_ID"), row);
        });
    }
}
